
/*
 *  Copyright (c) 2015. For Intelligent Group.
 *
 */

package com.intelligent.ispc.client.core.view.configuration;

import com.intelligent.ispc.client.core.controller.SystemController;
import com.intelligent.ispc.client.core.validator.*;
import com.intelligent.ispc.client.ex.JTextFieldEx;
import com.intelligent.ispc.client.utils.AppMessageFactory;
import com.intelligent.ispc.client.utils.GBC;
import com.intelligent.ispc.client.utils.validation.GuiComponentFactory;
import com.intelligent.ispc.client.utils.validation.ValidationUI;
import com.intelligent.ispc.common.utils.StringUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;

import com.intelligent.ispc.constant.AppConstant;
import org.apache.commons.lang.ArrayUtils;
import org.jdesktop.beansbinding.BindingGroup;
import org.jdesktop.jxlayer.JXLayer;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Set;

/**
 * Created by Lucien.chen on 2016/8/22.
 */
@org.springframework.stereotype.Component
public class AnalysisConfigPanel extends JPanel {

    private boolean[] alreadyInitPanel;

    @Autowired
    private SystemController systemController;

    private SysGrrDto grrConfigDto;
    private SysSpcDto spcConfigDto;
    private List<String> grrKeys;
    private BindingGroup grrBg;
    private BindingGroup spcBg;

    /**
     * construction
     */
    public AnalysisConfigPanel() {

    }

    /**
     * init data
     */
    public void initData() {
        grrKeys = systemController.getGrrKeys();
        alreadyInitPanel = new boolean[2];
        initPanelWithIndex();
        isSpcSaveFlag = true;
        isGrrSaveFlag = true;
    }

    /**
     * show a Dialog about "Whether or not to leave?"
     *
     * @return choice to leave
     */
    public boolean changePanelMessage() {
        if (isSaveChange()) {
            return true;
        }
        int choice = AppMessageFactory.showConfirmDialog("Data is not saved! Whether or not to leave?");
        if (choice == AppMessageFactory.CANCEL_OPTION) {
            return false;
        }
        return true;
    }

    /**
     * when save spc config finish for success
     * show a dialog
     */
    public void spcSaveSuccess() {
        isSpcSaveFlag = true;
        AppMessageFactory.showSuccessDialog("Save Successful");
    }

    /**
     * when save spc config finish for fail
     * show a dialog
     */
    public void spcSaveFail() {
        isSpcSaveFlag = false;
        AppMessageFactory.showErrorDialog("Save Failed");
    }

    /**
     * when grr spc config finish for success
     * show a dialog
     */
    public void grrSaveSuccess() {
        isGrrSaveFlag = true;
        AppMessageFactory.showSuccessDialog("Save Successful");
    }

    /**
     * when save grr config finish for fail
     * show a dialog
     */
    public void grrSaveFail() {
        isGrrSaveFlag = false;
        AppMessageFactory.showErrorDialog("Save Failed");
    }

    @PostConstruct
    private void initComponents() {

        tabPanel = new JTabbedPane();
        this.setLayout(new GridBagLayout());
        alreadyInitPanel = new boolean[2];

        spcSettingPanel = new JPanel();
        grrSettingPanel = new JPanel();

        tabPanel.addTab("SPC Setting", spcSettingPanel);
        tabPanel.addTab("GRR Setting", grrSettingPanel);
        this.add(tabPanel, new GBC(0, 1).setFill(GBC.BOTH).setWeight(100, 20));

        tabPanel.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                initPanelWithIndex();
            }
        });
    }

    private void initPanelWithIndex() {
        int index = tabPanel.getSelectedIndex();
        if (index >= tabPanel.getComponentCount() || alreadyInitPanel[index]) {
            return;
        }
        if (index == 0) {
            initSpcSettingPanel();
        } else {
            initGrrSettingPanel();
        }
    }

    private void initSpcSettingPanel() {
        spcConfigDto = systemController.findSpcConfig();
        spcBg = new BindingGroup();

        if (spcSettingPanel != null) {
            spcSettingPanel.removeAll();
        } else {
            spcSettingPanel = new javax.swing.JPanel();
        }
        spcSettingPanel.setLayout(new GridBagLayout());

        JPanel digitPanel = new JPanel();
        digitPanel.setLayout(new GridBagLayout());
        digitPanel.setBorder(BorderFactory.createTitledBorder("Analysis decimal setting"));

        JLabel digitLabel = new JLabel();
        digitLabel.setText("Decimal places");
        digitPanel.add(digitLabel, new GBC(0, 0).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(4, 100));
        JXLayer<JTextComponent> digitText = GuiComponentFactory.createTextField(spcBg, spcConfigDto, spcConfigDto.PROPERTYNAME_DIGIT);
        digitPanel.add(digitText, new GBC(1, 0).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(6, 100).setInsets(0, 0, 5, 5));
        digitPanel.add(new JLabel("(Input between 0 and 10)"), new GBC(2, 0).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));

        //draw group number
        JPanel groupNumPanel = new JPanel();
        groupNumPanel.setLayout(new GridBagLayout());
        groupNumPanel.setBorder(BorderFactory.createTitledBorder("Group Number"));
        int rowIndex = 0;

        JLabel distributionLabel = new JLabel();
        distributionLabel.setText("Distribution of number of clusters");
        distributionLabel.setFont(distributionLabel.getFont().deriveFont(Font.BOLD));
        groupNumPanel.add(distributionLabel, new GBC(0, rowIndex, 3, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));
        rowIndex++;

        ButtonGroup distributionNumGroup = new ButtonGroup();
        JRadioButton firDistributionButton = new JRadioButton("The default group, the square root of N integer upwards");
        JRadioButton secDistributionButton = new JRadioButton("Custom group");
        distributionNumGroup.add(firDistributionButton);
        distributionNumGroup.add(secDistributionButton);

        JXLayer<JTextComponent> distributionText = GuiComponentFactory.createTextField(spcBg, spcConfigDto, spcConfigDto.PROPERTYNAME_SPCNDGROUPKEY);

        if (StringUtils.isBlank(spcConfigDto.getSpcNdGroupKey())) {
            firDistributionButton.setSelected(true);
            distributionText.getView().setEditable(false);
        } else {
            secDistributionButton.setSelected(true);
            ((ValidationUI) distributionText.getUI()).setGroup(GroupKeys.class);
        }
        firDistributionButton.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                distributionText.getView().setEditable(false);
                ((ValidationUI) distributionText.getUI()).setGroup(null);
                spcConfigDto.setSpcNdGroupKey(null);
                spcConfigDto.setNdGroupKey(false);
            }
        });
        secDistributionButton.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                distributionText.getView().setEditable(true);
                ((ValidationUI) distributionText.getUI()).setGroup(GroupKeys.class);
                spcConfigDto.setSpcNdGroupKey(null);
                spcConfigDto.setNdGroupKey(true);
            }
        });

        groupNumPanel.add(firDistributionButton, new GBC(0, rowIndex, 3, 1).setAnchor(GBC.NORTHWEST).setWeight(100, 100));
        rowIndex++;
        groupNumPanel.add(secDistributionButton, new GBC(0, rowIndex).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(4, 100));
        groupNumPanel.add(distributionText, new GBC(1, rowIndex).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(10, 100));
        groupNumPanel.add(new JLabel(), new GBC(2, rowIndex).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));
        rowIndex++;

        JLabel controlChartLabel = new JLabel();
        controlChartLabel.setText("Control chart the number of clusters");
        controlChartLabel.setFont(controlChartLabel.getFont().deriveFont(Font.BOLD));
        groupNumPanel.add(controlChartLabel, new GBC(0, rowIndex, 3, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));
        rowIndex++;

        ButtonGroup controlChartGroup = new ButtonGroup();
        JRadioButton firControlChartButton = new JRadioButton("The default group, the square root of N integer upwards");
        JRadioButton secControlChartButton = new JRadioButton("Custom group");
        controlChartGroup.add(firControlChartButton);
        controlChartGroup.add(secControlChartButton);
        JXLayer<JTextComponent> controlChartText = GuiComponentFactory.createTextField(spcBg, spcConfigDto, spcConfigDto.PROPERTYNAME_SPCCCGROUPKEY);
        if (StringUtils.isBlank(spcConfigDto.getSpcCcGroupKey())) {
            firControlChartButton.setSelected(true);
            controlChartText.getView().setEditable(false);
        } else {
            secControlChartButton.setSelected(true);
            ((ValidationUI) controlChartText.getUI()).setGroup(GroupKeys.class);
        }
        firControlChartButton.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                controlChartText.getView().setEditable(false);
                ((ValidationUI) controlChartText.getUI()).setGroup(null);
                spcConfigDto.setSpcCcGroupKey(null);
                spcConfigDto.setCcGroupKey(false);
            }
        });
        secControlChartButton.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                controlChartText.getView().setEditable(true);
                ((ValidationUI) controlChartText.getUI()).setGroup(GroupKeys.class);
                spcConfigDto.setSpcCcGroupKey(null);
                spcConfigDto.setCcGroupKey(true);
            }
        });

        groupNumPanel.add(firControlChartButton, new GBC(0, rowIndex, 3, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));
        rowIndex++;
        groupNumPanel.add(secControlChartButton, new GBC(0, rowIndex).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(4, 100));
        groupNumPanel.add(controlChartText, new GBC(1, rowIndex).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(10, 100));
        groupNumPanel.add(new JLabel(), new GBC(2, rowIndex).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));
        rowIndex++;

        //draw alarm rule
        JPanel alarmRulePanel = new JPanel();
        alarmRulePanel.setLayout(new GridBagLayout());
        alarmRulePanel.setBorder(BorderFactory.createTitledBorder("Alarm Rule"));

        String[] topLineName = new String[]{
                "Indice Name", "Excellence", "Well", "Accept ability", "Rectification"
        };
        for (int i = 0; i < topLineName.length; i++) {
            JLabel label = new JLabel();
            label.setText(topLineName[i]);
            if (i == 0) {
                alarmRulePanel.add(label, new GBC(0, 0).setAnchor(GBC.NORTHWEST).setWeight(20, 100));
            } else {
                alarmRulePanel.add(label, new GBC(i, 0).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
            }
        }
        String[] alarmRuleLabelName = new String[]{
                "CA(%)", "CP", "CPK", "CPL", "CPU"};
        for (int i = 0; i < alarmRuleLabelName.length; i++) {
            JLabel label = new JLabel();
            label.setText(alarmRuleLabelName[i]);
            alarmRulePanel.add(label, new GBC(0, i + 1).setAnchor(GBC.NORTHWEST).setWeight(20, 100));
            SysSpcCpwDto sysSpcDto = spcConfigDto.getSysSpcCpwDtos().get(i);
            JXLayer<JTextComponent> value1 = GuiComponentFactory.createTextField(spcBg, sysSpcDto, sysSpcDto.PROPERTYNAME_VALUE1);
            JXLayer<JTextComponent> value2 = GuiComponentFactory.createTextField(spcBg, sysSpcDto, sysSpcDto.PROPERTYNAME_VALUE2);
            JXLayer<JTextComponent> value3 = GuiComponentFactory.createTextField(spcBg, sysSpcDto, sysSpcDto.PROPERTYNAME_VALUE3);
            JXLayer<JTextComponent> value4 = GuiComponentFactory.createTextField(spcBg, sysSpcDto, sysSpcDto.PROPERTYNAME_VALUE4);
            alarmRulePanel.add(value1, new GBC(1, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
            alarmRulePanel.add(value2, new GBC(2, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
            alarmRulePanel.add(value3, new GBC(3, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
            alarmRulePanel.add(value4, new GBC(4, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
        }
        JLabel messageLabel = new JLabel();
        alarmRulePanel.add(messageLabel, new GBC(0, alarmRuleLabelName.length + 2, 2, 1));
        for (int i = 0; i < spcConfigDto.getSysSpcCpwDtos().size(); i++) {
            spcConfigDto.getSysSpcCpwDtos().get(i).addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    isSpcSaveFlag = false;
                    if (!compareCpwGroup()) {
                        messageLabel.setText("<html><font style=\"color:red;\">" + "Can not compare with targets." + "</font><html>");
                    } else {
                        messageLabel.setText(null);
                    }
                }
            });
        }

        //draw control alarm rule
        JPanel controlAlarmRulePanel = new JPanel();
        controlAlarmRulePanel.setLayout(new GridBagLayout());
        controlAlarmRulePanel.setBorder(BorderFactory.createTitledBorder("Control Alarm Rule"));

        String[] controlAlarmLineName = new String[]{
                "Rule Name", "Is Analyse", "Current Rule", "n", "m", "s"
        };
        for (int i = 0; i < controlAlarmLineName.length; i++) {
            JLabel label = new JLabel(controlAlarmLineName[i]);
            if (i == 0) {
                controlAlarmRulePanel.add(label, new GBC(0, 0).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100));
            } else {
                controlAlarmRulePanel.add(label, new GBC(i, 0).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));
            }
        }

        String[] controlAlarmLabelName = new String[]{
                "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8"};
        String[] currentRuleName = new String[]{
                "[n] point falls outside the [s]σ limit from the centerline", "[n](or more) consecutive points fall on the same side of the centerline",
                "[n] (or more) points in a row are continually increasing or decreasing", "[n] points in a row alternate in direction, increasing then decreasing",
                "[m] out of [n] consecutive points fall beyond the [s]σ limit, on the same side of the centerline", "[m] out of the [n] consecutive points fall beyond the [s]σ limit, on the same side of the centerline",
                "[n] points in a row are all within the [s]σ limit, on either side of the centerline", "[n] points in a row exist with none within the [s]σ limit, and the points a in both directions from the centerline"
        };
        boolean[][] ruleView = {
                {true, false, true},
                {true, false, false},
                {true, false, false},
                {true, false, false},
                {true, true, true},
                {true, true, true},
                {true, false, true},
                {true, false, true}
        };

        for (int i = 0; i < controlAlarmLabelName.length; i++) {
            JLabel label = new JLabel();
            label.setText(controlAlarmLabelName[i]);
            controlAlarmRulePanel.add(label, new GBC(0, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100));

            SysSpcCcwDto sysSpcDto = spcConfigDto.getSysSpcCcwDtos().get(i);

            JXLayer<JCheckBox> checkBox = GuiComponentFactory.createCheckBox(spcBg, sysSpcDto, sysSpcDto.PROPERTYNAME_ANALYSE);
            controlAlarmRulePanel.add(checkBox, new GBC(1, i + 1).setAnchor(GBC.NORTHWEST).setWeight(20, 100));

            JLabel currentRuleLabel = new JLabel();
            currentRuleLabel.setText(currentRuleName[i]);
            controlAlarmRulePanel.add(currentRuleLabel, new GBC(2, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100));

            if (!ruleView[i][0]) {
                JTextFieldEx value1 = new JTextFieldEx();
                value1.setEditable(false);
                controlAlarmRulePanel.add(value1, new GBC(3, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
            } else {
                JXLayer<JTextComponent> value1 = GuiComponentFactory.createTextField(spcBg, sysSpcDto, sysSpcDto.PROPERTYNAME_VALUE1);
                controlAlarmRulePanel.add(value1, new GBC(3, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
            }

            if (!ruleView[i][1]) {
                JTextFieldEx value2 = new JTextFieldEx();
                value2.setEditable(false);
                controlAlarmRulePanel.add(value2, new GBC(4, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
            } else {
                JXLayer<JTextComponent> value2 = GuiComponentFactory.createTextField(spcBg, sysSpcDto, sysSpcDto.PROPERTYNAME_VALUE2);
                controlAlarmRulePanel.add(value2, new GBC(4, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
            }
            if (!ruleView[i][2]) {
                JTextFieldEx value3 = new JTextFieldEx();
                value3.setEditable(false);
                controlAlarmRulePanel.add(value3, new GBC(5, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
            } else {
                JXLayer<JTextComponent> value3 = GuiComponentFactory.createTextField(spcBg, sysSpcDto, sysSpcDto.PROPERTYNAME_VALUE3);
                controlAlarmRulePanel.add(value3, new GBC(5, i + 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(50, 100));
            }

            sysSpcDto.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    isSpcSaveFlag = false;
                }
            });

        }

        spcConfigDto.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                isSpcSaveFlag = false;
            }
        });

        JPanel savePanel = new JPanel();
        savePanel.setLayout(new GridBagLayout());
        JButton saveButton = new JButton();
        saveButton.setText("Save");
        saveButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                saveSpcConfig();
            }
        });
        savePanel.add(saveButton, new GBC(0, 0).setAnchor(GBC.NORTHWEST).setWeight(100, 100));

        JScrollPane spcScrollPanel = new JScrollPane();

        JPanel spcPanel = new JPanel();
        spcPanel.setLayout(new GridBagLayout());
        spcPanel.add(digitPanel, new GBC(0, 0).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 0));
        spcPanel.add(groupNumPanel, new GBC(0, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 0));
        spcPanel.add(alarmRulePanel, new GBC(0, 2).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 0));
        spcPanel.add(controlAlarmRulePanel, new GBC(0, 3).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 0));
        spcPanel.add(savePanel, new GBC(0, 4).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));

        spcScrollPanel.setViewportView(spcPanel);
        spcScrollPanel.setBorder(BorderFactory.createEmptyBorder());

        spcSettingPanel.add(spcScrollPanel, new GBC(0, 0).setFill(GBC.BOTH).setAnchor(GBC.NORTHWEST).setWeight(100, 100));
        alreadyInitPanel[0] = true;
    }

    private void initGrrSettingPanel() {
        grrConfigDto = systemController.findGrrConfig();
        grrBg = new BindingGroup();

        if (grrSettingPanel != null) {
            grrSettingPanel.removeAll();
        } else {
            grrSettingPanel = new javax.swing.JPanel();
        }
        grrSettingPanel.setLayout(new GridBagLayout());

        JPanel digitPanel = new JPanel();
        digitPanel.setLayout(new GridBagLayout());
        digitPanel.setBorder(BorderFactory.createTitledBorder("Analysis decimal setting"));

        JLabel digitLabel = new JLabel();
        digitLabel.setText("Decimal places");
        digitPanel.add(digitLabel, new GBC(0, 0).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(4, 100));
        JXLayer<JTextComponent> digitText = GuiComponentFactory.createTextField(spcBg, grrConfigDto, grrConfigDto.PROPERTYNAME_DIGIT);
        digitPanel.add(digitText, new GBC(1, 0).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(6, 100).setInsets(0, 0, 5, 5));
        digitPanel.add(new JLabel("(Input between 0 and 10)"), new GBC(2, 0).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));

        //draw default system
        JPanel defaultSettingPanel = new JPanel();
        defaultSettingPanel.setLayout(new GridBagLayout());
        defaultSettingPanel.setBorder(BorderFactory.createTitledBorder("GRR Default Setting"));

        JPanel modelPanel = new JPanel();
        modelPanel.setLayout(new GridBagLayout());

        JLabel modelLabel = new JLabel();
        modelLabel.setText("GRR Model");
        modelPanel.add(modelLabel, new GBC(0, 0, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100).setInsets(0, 0, 0, 5));

        JXLayer<JComboBox> schemeBox = GuiComponentFactory.createCombobox(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_SCHEME);
        String[] schemeCombo = {AppConstant.GRR_MODEL_NORMAL, AppConstant.GRR_MODEL_SLOT};
        LangBoxModel schemeModel = new LangBoxModel<Object>(schemeCombo);
        schemeModel.setSelectedItem(grrConfigDto.getScheme());
        schemeBox.getView().setModel(schemeModel);
        if (schemeBox.getView().getSelectedIndex() == -1) {
            schemeBox.getView().setSelectedIndex(0);
        }
        modelPanel.add(schemeBox, new GBC(1, 0, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100).setInsets(0, 0, 5, 5));

        JLabel firChangelLabel = new JLabel();
        firChangelLabel.setText("First Change");
        modelPanel.add(firChangelLabel, new GBC(2, 0, 1, 1).setAnchor(GBC.NORTHWEST).setWeight(100, 100).setInsets(0, 0, 0, 5));

        JXLayer<JComboBox> firchBox = GuiComponentFactory.createCombobox(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_FIRSTCHANGE);
        String[] firchCombo = {AppConstant.GRR_FIRST_CHANGE_OPERATOR, AppConstant.GRR_FIRST_CHANGE_TRIAL};
        LangBoxModel firchModel = new LangBoxModel<Object>(firchCombo);
        firchModel.setSelectedItem(grrConfigDto.getFirstChange());
        firchBox.getView().setModel(firchModel);
        if (firchBox.getView().getSelectedIndex() == -1) {
            firchBox.getView().setSelectedIndex(0);
        }
        modelPanel.add(firchBox, new GBC(3, 0, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100).setInsets(0, 0, 5, 5));


        JLabel sigmaLabel = new JLabel();
        sigmaLabel.setText("Default Sigma");
        modelPanel.add(sigmaLabel, new GBC(0, 1, 1, 1).setAnchor(GBC.NORTHWEST).setWeight(100, 100).setInsets(0, 0, 0, 5));

        JXLayer<JComboBox> sigmaBox = GuiComponentFactory.createCombobox(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_SIGMA);
        String[] sigmaCombo = {"6.0", "5.15"};
        LangBoxModel sigmaModel = new LangBoxModel<Object>(sigmaCombo);
        sigmaModel.setSelectedItem(grrConfigDto.getSigma());
        sigmaBox.getView().setModel(sigmaModel);
        if (sigmaBox.getView().getSelectedIndex() == -1) {
            sigmaBox.getView().setSelectedIndex(0);
        }
        modelPanel.add(sigmaBox, new GBC(1, 1, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100).setInsets(0, 0, 5, 5));
        modelPanel.add(new Label(), new GBC(2, 1, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));

        JPanel settingPanel = new JPanel();
        settingPanel.setLayout(new GridBagLayout());

        String[] firLineName = {
                "Parts", "Apraisers", "Trails"
        };
        insertLineToPanel(settingPanel, firLineName, 0);

        JXLayer<JTextComponent> partsField = GuiComponentFactory.createTextField(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_PARTS);
        settingPanel.add(partsField, new GBC(0, 1, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(80, 100).setInsets(0, 0, 0, 5));

        JXLayer<JTextComponent> appraisersField = GuiComponentFactory.createTextField(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_APPRAISERS);
        settingPanel.add(appraisersField, new GBC(1, 1, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(80, 100).setInsets(0, 0, 0, 5));

        JXLayer<JTextComponent> trailsField = GuiComponentFactory.createTextField(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_TRAILS);
        settingPanel.add(trailsField, new GBC(2, 1, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(80, 100).setInsets(0, 0, 0, 5));


        settingPanel.add(new Label(), new GBC(3, 0, 1, 1).setFill(GBC.BOTH).setAnchor(GBC.NORTHWEST).setWeight(100, 100));

        String[] secLineName = {
                "Excellent", "Adequate", "Marginal"
        };
        insertLineToPanel(settingPanel, secLineName, 2);

        JXLayer<JTextComponent> excellentField = GuiComponentFactory.createTextField(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_EXCELLENT);
        settingPanel.add(excellentField, new GBC(0, 3, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(80, 100).setInsets(0, 0, 0, 5));

        JXLayer<JTextComponent> adequateField = GuiComponentFactory.createTextField(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_ADEQUATE);
        settingPanel.add(adequateField, new GBC(1, 3, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(80, 100).setInsets(0, 0, 0, 5));

        JXLayer<JTextComponent> marginalField = GuiComponentFactory.createTextField(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_MARGINAL);
        settingPanel.add(marginalField, new GBC(2, 3, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(80, 100).setInsets(0, 0, 0, 5));

        JLabel ruleAlarm = new JLabel();
        settingPanel.add(ruleAlarm, new GBC(0, 4, 3, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(80, 100));

        JPanel groupPanel = new JPanel();
        groupPanel.setLayout(new GridBagLayout());
        String[] tirLineName = {
                "Group 1", "Group 2"
        };
        JLabel groupLabel1 = new JLabel("<html>" + tirLineName[0] + "<font style=\"color:red;\">" + "*" + "</font><html>");
        groupPanel.add(groupLabel1, new GBC(0, 0, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100));
        String[] item = {""};
        String[] comboItems = (String[]) ArrayUtils.addAll(item, grrKeys.toArray());
        JXLayer<JComboBox> group1ComboBox = GuiComponentFactory.createCombobox(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_GROUP1KEY);
        LangBoxModel group1Model = new LangBoxModel<Object>(comboItems);
        group1Model.setSelectedItem(grrConfigDto.getGroup1Key());
        group1ComboBox.getView().setModel(group1Model);
        if (group1ComboBox.getView().getSelectedIndex() == -1) {
            group1ComboBox.getView().setSelectedIndex(0);
        }
        groupPanel.add(group1ComboBox, new GBC(0, 1, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100).setInsets(0, 0, 5, 5));

        groupPanel.add(new Label(), new GBC(2, 0, 1, 1).setAnchor(GBC.NORTHWEST).setWeight(100, 100));
        groupPanel.add(new Label(), new GBC(3, 0, 1, 1).setAnchor(GBC.NORTHWEST).setWeight(100, 100));

        JLabel groupLabel2 = new JLabel(tirLineName[1]);
        groupPanel.add(groupLabel2, new GBC(1, 0, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100));
        JXLayer<JComboBox> group2ComboBox = GuiComponentFactory.createCombobox(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_GROUP2KEY);
        LangBoxModel group2Model = new LangBoxModel<Object>(comboItems);
        group2Model.setSelectedItem(grrConfigDto.getGroup2Key());
        group2ComboBox.getView().setModel(group2Model);
        if (group2ComboBox.getView().getSelectedIndex() == -1) {
            group2ComboBox.getView().setSelectedIndex(0);
        }
        groupPanel.add(group2ComboBox, new GBC(1, 1, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100).setInsets(0, 0, 5, 5));

        String[] forLineName = {
                "Part", "Operation"
        };
        JLabel partLabel = new JLabel("<html>" + forLineName[0] + "<font style=\"color:red;\">" + "*" + "</font><html>");
        groupPanel.add(partLabel, new GBC(0, 2, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100));

        JXLayer<JComboBox> partComboBox = GuiComponentFactory.createCombobox(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_PARTKEY);
        LangBoxModel partModel = new LangBoxModel<Object>(comboItems);
        partModel.setSelectedItem(grrConfigDto.getPartKey());
        partComboBox.getView().setModel(partModel);
        if (partComboBox.getView().getSelectedIndex() == -1) {
            partComboBox.getView().setSelectedIndex(0);
        }
        groupPanel.add(partComboBox, new GBC(0, 3, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100).setInsets(0, 0, 5, 5));


        JLabel operaLabel = new JLabel("<html>" + forLineName[1] + "<font style=\"color:red;\">" + "*" + "</font><html>");
        groupPanel.add(operaLabel, new GBC(1, 2, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100));

        JXLayer<JComboBox> operatorComboBox = GuiComponentFactory.createCombobox(grrBg, grrConfigDto, grrConfigDto.PROPERTYNAME_OPERATORKEY);
        LangBoxModel operatorModel = new LangBoxModel<Object>(comboItems);
        operatorModel.setSelectedItem(grrConfigDto.getOperatorKey());
        operatorComboBox.getView().setModel(operatorModel);
        if (operatorComboBox.getView().getSelectedIndex() == -1) {
            operatorComboBox.getView().setSelectedIndex(0);
        }
        ((ValidationUI) operatorComboBox.getUI()).setGroup(Slot.class);
        groupPanel.add(operatorComboBox, new GBC(1, 3, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(20, 100).setInsets(0, 0, 5, 5));

        JLabel groupAlarm = new JLabel();
        groupPanel.add(groupAlarm, new GBC(0, 4, 3, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(80, 100));

        grrConfigDto.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                isGrrSaveFlag = false;
                if (compareRule()) {
                    ruleAlarm.setText("");
                } else {
                    ruleAlarm.setText("<html><font style=\"color:red;\">" + "Can not compare with targets." + "</font><html>");
                }
                if (compareGroup()) {
                    groupAlarm.setText("");
                } else {
                    groupAlarm.setText("<html><font style=\"color:red;\">" + "Can not compare with targets." + "</font><html>");
                }

            }
        });
        defaultSettingPanel.add(modelPanel, new GBC(0, 1).setFill(GBC.NONE).setAnchor(GBC.NORTHWEST).setWeight(100, 100).setInsets(0, 0, 5, 0));
        defaultSettingPanel.add(settingPanel, new GBC(0, 2).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100).setInsets(0, 0, 5, 0));
        defaultSettingPanel.add(groupPanel, new GBC(0, 3).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100).setInsets(0, 0, 5, 0));

        JPanel savePanel = new JPanel();
        savePanel.setLayout(new GridBagLayout());
        JButton saveButton = new JButton();
        saveButton.setText("Save");
        saveButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                saveGrrConfig();
            }
        });
        savePanel.add(saveButton, new GBC(0, 0).setAnchor(GBC.NORTHWEST).setWeight(100, 100));

        if (schemeBox.getView().getSelectedIndex() != 0) {
            firChangelLabel.setVisible(false);
            firchBox.setVisible(false);
            operaLabel.setVisible(true);
            operatorComboBox.setVisible(true);
        } else {
            firChangelLabel.setVisible(true);
            firchBox.setVisible(true);
            operaLabel.setVisible(false);
            operatorComboBox.setVisible(false);
            operatorComboBox.getView().setSelectedIndex(0);
        }
        schemeBox.getView().addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                changeScheme(schemeBox, firChangelLabel, firchBox, operaLabel, operatorComboBox);
            }
        });

        grrSettingPanel.add(digitPanel, new GBC(0, 0).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 0));
        grrSettingPanel.add(defaultSettingPanel, new GBC(0, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 0));
        grrSettingPanel.add(savePanel, new GBC(0, 2).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(100, 100));
        alreadyInitPanel[1] = true;
    }

    /*
     * set visible when change scheme between SLOT AND NORMOL
     */
    private void changeScheme(JXLayer<JComboBox> schemeBox, JLabel firChangelLabel, JXLayer<JComboBox> firchBox, JLabel operaLabel, JXLayer<JComboBox> operatorComboBox) {
        if (schemeBox.getView().getSelectedIndex() != 0) {
            firChangelLabel.setVisible(false);
            firchBox.setVisible(false);
            operaLabel.setVisible(true);
            operatorComboBox.setVisible(true);
        } else {
            firChangelLabel.setVisible(true);
            firchBox.setVisible(true);
            operaLabel.setVisible(false);
            operatorComboBox.setVisible(false);
            grrConfigDto.setOperatorKey(null);
            operatorComboBox.getView().setSelectedIndex(0);
        }
    }

    /*
    *add a line of Labels to panel
     */
    private void insertLineToPanel(JPanel panel, String[] name, int y) {
        for (int i = 0; i < name.length; i++) {
            String redSignName;
            redSignName = "<html>" + name[i] + "<font style=\"color:red;\">" + "*" + "</font><html>";
            JLabel label = new JLabel(redSignName);
            panel.add(label, new GBC(i, y, 1, 1).setFill(GBC.HORIZONTAL).setAnchor(GBC.NORTHWEST).setWeight(80, 100));
        }
    }

    private boolean isSaveChange() {
        return isSpcSaveFlag && isGrrSaveFlag;
    }

    /*
     *save spc config after validated finish
     */
    private void saveSpcConfig() {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        List<SysSpcCpwDto> sysSpcCpwDtos = spcConfigDto.getSysSpcCpwDtos();
        List<SysSpcCcwDto> sysSpcCcwDtos = spcConfigDto.getSysSpcCcwDtos();
        for (int i = 0; i < sysSpcCpwDtos.size(); i++) {
            Set<ConstraintViolation<SysSpcCpwDto>> validationMessages = validator.validate(sysSpcCpwDtos.get(i));
            if (validationMessages.size() > 0) {
                spcSaveFail();
                return;
            }
        }
        for (int i = 0; i < sysSpcCcwDtos.size(); i++) {
            Set<ConstraintViolation<SysSpcCcwDto>> validationMessages = validator.validate(sysSpcCcwDtos.get(i));
            if (validationMessages.size() > 0) {
                spcSaveFail();
                return;
            }
        }
        if (spcConfigDto.isNdGroupKey()) {
            Set<ConstraintViolation<SysSpcDto>> validationMessages = validator.validateProperty(spcConfigDto, spcConfigDto.PROPERTYNAME_SPCNDGROUPKEY, GroupKeys.class);
            if (validationMessages.size() > 0) {
                spcSaveFail();
                return;
            }
        }
        if (spcConfigDto.isCcGroupKey()) {
            Set<ConstraintViolation<SysSpcDto>> validationMessages = validator.validateProperty(spcConfigDto, spcConfigDto.PROPERTYNAME_SPCCCGROUPKEY, GroupKeys.class);
            if (validationMessages.size() > 0) {
                spcSaveFail();
                return;
            }
        }
        Set<ConstraintViolation<SysSpcDto>> digitValidationMessages = validator.validateProperty(spcConfigDto, spcConfigDto.PROPERTYNAME_DIGIT);
        if (digitValidationMessages.size() > 0) {
            spcSaveFail();
            return;
        }

        if (!compareCpwGroup()) {
            spcSaveFail();
            return;
        }

        systemController.saveSpcConfig(spcConfigDto);
    }

    /*
    *save spc config after validated finish
    */
    private void saveGrrConfig() {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<SysGrrDto>> validationMessages = validator.validate(grrConfigDto);
        Set<ConstraintViolation<SysGrrDto>> groupValidation = validator.validateProperty(grrConfigDto, grrConfigDto.PROPERTYNAME_OPERATORKEY, Slot.class);
        if (validationMessages.size() == 0 && compareRule() && compareGroup()) {
            if (grrConfigDto.getScheme().equals(AppConstant.GRR_MODEL_SLOT) && groupValidation.size() > 0) {
                grrSaveFail();
            } else {
                systemController.saveGrrConfig(grrConfigDto);
            }
        } else {
            grrSaveFail();
        }
    }

    /*
     *validated spc Cpw
     */
    private boolean compareCpwGroup() {
        List<SysSpcCpwDto> sysSpcCpwDtos = spcConfigDto.getSysSpcCpwDtos();
        String excellence = sysSpcCpwDtos.get(0).getValue1();
        String well = sysSpcCpwDtos.get(0).getValue2();
        String acceptAblility = sysSpcCpwDtos.get(0).getValue3();
        String rectification = sysSpcCpwDtos.get(0).getValue4();
        if (StringUtils.isNumeric(excellence) && StringUtils.isNumeric(well) && StringUtils.isNumeric(acceptAblility) && StringUtils.isNumeric(rectification)) {
            if (Double.valueOf(excellence) > Double.valueOf(well) || Double.valueOf(well) > Double.valueOf(acceptAblility) || Double.valueOf(acceptAblility) > Double.valueOf(rectification)) {
                return false;
            }
        }
        for (int i = 1; i < sysSpcCpwDtos.size(); i++) {
            String value1 = sysSpcCpwDtos.get(i).getValue1();
            String value2 = sysSpcCpwDtos.get(i).getValue2();
            String value3 = sysSpcCpwDtos.get(i).getValue3();
            String value4 = sysSpcCpwDtos.get(i).getValue4();
            if (StringUtils.isNumeric(value1) && StringUtils.isNumeric(value2) && StringUtils.isNumeric(value3) && StringUtils.isNumeric(value4)) {
                if (Double.valueOf(value1) < Double.valueOf(value2) || Double.valueOf(value2) < Double.valueOf(value3) || Double.valueOf(value3) < Double.valueOf(value4)) {
                    return false;
                }
            }
        }
        return true;
    }

    /*
     *vadalied grr rule
     */
    private boolean compareRule() {
        String excellent = grrConfigDto.getExcellent();
        String adequate = grrConfigDto.getAdequate();
        String marginal = grrConfigDto.getMarginal();
        if (StringUtils.isNumeric(excellent) && StringUtils.isNumeric(adequate) && StringUtils.isNumeric(marginal)) {
            if (Double.valueOf(excellent) > Double.valueOf(adequate) || Double.valueOf(adequate) > Double.valueOf(marginal)) {
                return false;
            }
        }
        return true;
    }

    /*
     *vadalied grr group
     */
    private boolean compareGroup() {
        if (!grrConfigDto.getScheme().equals(AppConstant.GRR_MODEL_NORMAL)) {
            String[] keys = {
                    grrConfigDto.getGroup1Key(), grrConfigDto.getGroup2Key(), grrConfigDto.getPartKey(), grrConfigDto.getOperatorKey()
            };
            return compareString(keys);
        } else {
            String[] keys = {
                    grrConfigDto.getGroup1Key(), grrConfigDto.getGroup2Key(), grrConfigDto.getPartKey()
            };
            return compareString(keys);
        }

    }

    /*
     * are Strings whether unique or not?
     */
    private boolean compareString(String[] keys) {
        for (int i = 0; i < keys.length; i++) {
            for (int j = i + 1; j < keys.length; j++) {
                if (keys[i].equals(keys[j]) && !StringUtils.isBlank(keys[i])) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean isSpcSaveFlag = true;

    private boolean isGrrSaveFlag = true;

    private JPanel spcSettingPanel;
    private JPanel grrSettingPanel;
    private JTabbedPane tabPanel;
}
